﻿#include "channelchatroom.h"
#include "ui_chatroom.h"
#include <librtc.h>
#include <QMenu>
#include "clientcallback.h"
#include "globaltools.h"
#include "protohash.h"

#define FUN_MGR_MIC_ORDER 1015 //麦序管理

ChannelChatRoom::ChannelChatRoom(const ChannelInfo &channel_info, QWidget *parent) : ChatRoom(channel_info, parent)
{
    //ui->videoLayout->resetGrid(1, 1);
    ClientCallback::instance()->channel_get_onlines(channel_info.rid);
}

ChannelChatRoom::~ChannelChatRoom()
{
    if(acting_button)
        ClientCallback::instance()->channel_free_mic(getId());
}

void ChannelChatRoom::handle_msg(int type, const QVariantHash &msg)
{
    handle_text_msg(type, msg);
}

void ChannelChatRoom::handle_channel_event(int cmd_type, QVariantHash &msg, ChannelInfo &channel_info)
{
    if(getParam(msg, cmd_param_rid).toLongLong() != getId())
        return;
    if(cmd_type == cmd_type_ntfy_join)
    {
        handle_join(msg);
    }
    else if(cmd_type == cmd_type_ntfy_exit)
    {
        handle_exit(msg);
    }
    else if(cmd_type == cmd_type_room_msg)
    {
        handle_text_msg(getParam(msg, cmd_param_msg_type).toInt(), msg);
        //1.set read
        auto mids = channel_info.mark_read(getParam(msg, cmd_param_mid).toByteArray());
        //2.mark read
    }
    else if(cmd_type == cmd_type_ntfy_mic_state)
    {
        if(hasParam(msg, cmd_param_mic_ver))
        {
            handle_mic_state(channel_info.mic_list, channel_info.apply_list);
            if(channel_info.mic_changes.size() == 6)
                handle_mic_change(channel_info.mic_changes[0], channel_info.mic_changes[1],
                        channel_info.mic_changes[2], channel_info.mic_changes[3],
                        channel_info.mic_changes[4], channel_info.mic_changes[5]);
        }
    }
    else if(cmd_type == cmd_type_ack)
    {
        int command_type = getParam(msg, cmd_param_ack_cmd).toInt();
        int result = getParam(msg, cmd_param_code).toInt();
        if(command_type == cmd_type_get_room_onlines)
        {
            handle_onlines_ack(result, msg, channel_info);
            return;
        }
        QString text, resultStr, errStr;//%1:result,%2:err
        if (command_type == cmd_type_apply_mic)
        {
            if(result==error_none)
                return;
            text = QObject::trECSUTF8("分享视频%1%2");
        }
        else if(command_type == cmd_type_grant_mic)
        {
            if(result==error_none)
                return;
            text = QObject::trECSUTF8("分享到视频%1%2");
        }
        else if(command_type == cmd_type_free_mic)
        {
            if(result==error_none)
                return;
            text = QObject::trECSUTF8("关闭视频或取消等待%1%2");
        }
        else
            return;
        if(result==error_none)
            resultStr = (QObject::trECSUTF8("成功"));
        else
        {
            resultStr = (QObject::trECSUTF8("失败:\n"));
            if(errStr.isEmpty())
            {
                errStr = "(" + QString::number(result) + ")";
                errStr = ClientCallback::instance()->getErrorString(result);
            }
        }
        showNotifyText(text.arg(resultStr,errStr));
    }
}

void ChannelChatRoom::handle_join(QVariantHash &msg)
{
    auto user_info = ProtoHash::decodeHash(getParam(msg, cmd_param_user_info).toByteArray());
    if(qint64 uid = getParam(user_info ,cmd_param_uid).toLongLong())
    {
        online_list.insert(uid);
        auto basic_info = ProtoHash::decodeHash(getParam(msg, cmd_param_basic_info).toByteArray());
        QString name = getParam(basic_info ,cmd_param_name).toString();
        auto find = userListItems.find(uid);
        if(find == userListItems.constEnd())
        {
            //add
            auto listItem = new QListWidgetItem(ui->list_online_user);
            if(name.isEmpty())
                name = QString::number(uid);
            listItem->setText(name);
            listItem->setData(ID_ROLE, uid);
            listItem->setFlags(listItem->flags() & ~Qt::ItemIsSelectable);
            userListItems[uid] = listItem;
        }
        else if(auto finditem = find.value())
        {
            if(finditem->listWidget() == ui->list_offline_user)
            {
                ui->list_offline_user->takeItem(ui->list_offline_user->row(finditem));
                finditem->setFlags(finditem->flags() | Qt::ItemIsEnabled);
                ui->list_online_user->addItem(finditem);
            }
            //edit
            if(!name.isEmpty() && finditem->text() != name)
                finditem->setText(name);
        }
    }
}

void ChannelChatRoom::handle_exit(QVariantHash &msg)
{
    if(qint64 uid = getParam(msg, cmd_param_uid).toLongLong())
    {
        online_list.remove(uid);
        auto find = userListItems.find(uid);
        if(find != userListItems.constEnd())
        {
            if(!find.value())
                userListItems.erase(find);
            else if(find.value()->listWidget() == ui->list_online_user)   //如果item已经在offline则不用处理
            {
                if(auto item = ui->list_online_user->takeItem(ui->list_online_user->row(find.value())))
                {
                    //channel member
                    if(item->data(MEMEBR_ROLE).toBool())
                    {
                        item->setFlags(item->flags() & ~Qt::ItemIsEnabled);
                        ui->list_offline_user->addItem(item);
                    }
                    else
                    {
                        userListItems.erase(find);
                        delete item;
                    }
                }
            }
            stopNotifySpeak(uid);
        }
    }

}

void ChannelChatRoom::handle_onlines_ack(int result, QVariantHash &msg, const ChannelInfo &channel_info)
{
    if(result == error_none)
    {
        online_list.clear();
        for(const auto& user : getParam(msg, cmd_param_room_list).toByteArray().split(';'))
        {
            qint64 uid = user.toLongLong();
            if(uid > 0)
                online_list.insert(uid);
        }
        refreshUserListViews(channel_info.member_list);
    }
}

void ChannelChatRoom::handle_mic_change(const QSet<qint64> &old_audio, const QSet<qint64> &new_audio,
                                 const QSet<qint64> &old_video, const QSet<qint64> &new_video,
                                 const QSet<qint64> &old_apply, const QSet<qint64> &new_apply)
{
    const qint64 myid = ClientCallback::instance()->get_my_id();

    if(new_video.contains(myid))
    {
        //上视频
        acting_button = ui->button_camera;
        setButtonStatus(1, -1, -1);
        setVideoEffect(true, true);
        //开视频时自动静音
        ui->button_micphone->setChecked(true);
    }
    else if(new_audio.contains(myid))
    {
        //开音频
        if(acting_button == ui->button_tospeak)
        {
            setButtonStatus(-1, -1, 0);
        }
        else if(acting_button == this)    //键盘快捷键
        {
            setButtonStatus(-1, -1, -1);
        }
        else if(acting_button == ui->button_meeting)
        {
            acting_button = ui->button_meeting;
            setButtonStatus(-1, 1, -1);
        }
    }
    else if(new_apply.contains(myid))
    {
        if(acting_button == ui->button_camera)
        {
            setButtonStatus(1, -1, -1);
        }
        else if(acting_button == ui->button_tospeak)
        {
            setButtonStatus(-1, -1, 0);
        }
        else if(acting_button == ui->button_meeting)
        {
            setButtonStatus(-1, 1, -1);
        }
        else if(acting_button == this)
        {
            setButtonStatus(-1, -1, -1);
        }
        else    //异常
            ClientCallback::instance()->channel_free_mic(getId());
    }
    else
    {
        if(old_video.contains(myid))
        {
            //下麦
            setVideoEffect(false, true);
        }
        if((old_audio + old_video + old_apply - new_audio - new_video).contains(myid))
        {
            setButtonStatus(0, 0, 0);
            //下麦时自动解除静音
            ui->button_micphone->setChecked(false);
        }
    }
    if((new_video + new_audio - old_audio - old_video).contains(myid))
    {
        self_speaking = true;
        ui->button_tospeak->setStyleSheet(QLatin1String("background-image: url(:/gui/mic_strength_1.png)"));
        volumeCalculated = volumeShowing = 1;
    }
    else if((old_audio + old_video - new_audio - new_video).contains(myid))
    {
        self_speaking = false;
        volumeTimer.stop();
        volumeCalculated = volumeShowing = 0;
        ui->button_tospeak->setStyleSheet(QString());
    }
    if(applyTimer.isActive())
    {
        applyTimer.stop();
        if(acting_button == ui->button_camera && !ui->button_camera->isEnabled())
            ui->button_camera->setEnabled(true);
        else if(acting_button == ui->button_meeting && !ui->button_meeting->isEnabled())
            ui->button_meeting->setEnabled(true);
    }
    for(auto over : old_audio + old_video)
    {
        if(new_audio.contains(over) || new_video.contains(over))
            continue;
        if(auto item = userListItems.value(over, Q_NULLPTR))
        {
            item->setText(item->data(NAME_ROLE).toString());
            item->setData(VIDEO_ROLE, false);
            item->setData(MIC_ROLE, 0);
        }
    }
    for(auto audio_start : new_audio)
    {
        if(auto item = userListItems.value(audio_start, Q_NULLPTR))
        {
            item->setData(VIDEO_ROLE, false);
            //item->setData(MIC_ROLE, );
        }
    }
    for(auto video_start : new_video)
    {
        if(auto item = userListItems.value(video_start, Q_NULLPTR))
        {
            item->setData(VIDEO_ROLE, true);
            //item->setData(MIC_ROLE, );
        }
    }
}

void ChannelChatRoom::timerEvent(QTimerEvent *e)
{
    if(e->timerId() == applyTimer.timerId())
    {
        applyTimer.stop();
        if(!ui->button_camera->isEnabled() && ui->button_camera->toolTip().isEmpty())
        {
            ui->button_camera->setEnabled(true);
            if(acting_button == ui->button_camera)
                acting_button = Q_NULLPTR;
        }
        if(!ui->button_meeting->isEnabled() && ui->button_meeting->toolTip().isEmpty())
        {
            ui->button_meeting->setEnabled(true);
            if(acting_button == ui->button_meeting)
                acting_button = Q_NULLPTR;
        }
    }
    ChatRoom::timerEvent(e);
}

QByteArray ChannelChatRoom::send_msg(int msg_type, const QString &text)
{
    ClientCallback::instance()->channel_send_msg(getId(), getName(ClientCallback::instance()->get_my_id()), msg_type, text);
    //频道不显示已读未读，所以返回空mid
    return QByteArray();
}

void ChannelChatRoom::startSpeak()
{
    ChatRoom::startSpeak();
    ClientCallback::instance()->channel_apply_ptt(getId());
}

void ChannelChatRoom::stopSpeak()
{
    ClientCallback::instance()->channel_free_mic(getId());
}

void ChannelChatRoom::slot_free_mic()
{
    if(auto action = qobject_cast<QAction*>(sender()))
    {
        if(auto uid = action->data().toLongLong())
        {
            ClientCallback::instance()->channel_free_mic(getId(), uid);
        }
    }
}

void ChannelChatRoom::slot_grant_mic()
{
    if(auto action = qobject_cast<QAction*>(sender()))
    {
        auto varList = action->data().toList();
        if(varList.size() != 2)
            return;
        auto uid = varList.at(0).toLongLong();
        auto mid = varList.at(1).toInt();
        if(uid > 0 && mid > 0)
        {
            ClientCallback::instance()->channel_grant_mic(getId(), uid, mid);
        }
    }
}

void ChannelChatRoom::on_button_meeting_clicked(bool checked)
{
    ui->button_meeting->setChecked(!checked);
    if(checked && acting_button == Q_NULLPTR)
    {
        acting_button = ui->button_meeting;
        setButtonStatus(-1, 0, -1);
        ui->button_meeting->setEnabled(false);
        applyTimer.start(5000, this);
        startSpeak();
    }
    else if(!checked && acting_button == ui->button_meeting)
    {
        acting_button = Q_NULLPTR;
        setButtonStatus(-1, 1, -1);
        ui->button_meeting->setEnabled(false);
        applyTimer.start(5000, this);
        stopSpeak();
    }
}

void ChannelChatRoom::on_button_camera_clicked(bool checked)
{
    ui->button_camera->setChecked(!checked);
    if(checked && acting_button == Q_NULLPTR)
    {
        acting_button = ui->button_camera;
        setButtonStatus(0, -1, -1);
        ui->button_camera->setEnabled(false);
        applyTimer.start(5000, this);
        ClientCallback::instance()->channel_apply_video(getId());
    }
    else if(!checked && acting_button == ui->button_camera)
    {
        acting_button = Q_NULLPTR;
        setButtonStatus(1, -1, -1);
        ui->button_camera->setEnabled(false);
        applyTimer.start(5000, this);
        ClientCallback::instance()->channel_free_mic(getId());
    }
}

void ChannelChatRoom::on_list_online_user_customContextMenuRequested(const QPoint &pos)
{
    if(auto item = ui->list_online_user->itemAt(pos))
    {
        if(!item->flags().testFlag(Qt::ItemIsEnabled))  //不在线
            return;
        qint64 uid = item->data(ID_ROLE).toLongLong();
        if(!uid)
            return;
        const qint64 myid = ClientCallback::instance()->get_my_id();
        auto menu = new QMenu(this);
        menu->setAttribute(Qt::WA_DeleteOnClose);
        QAction* action = Q_NULLPTR;

        if(hasFunction(FUN_MGR_MIC_ORDER))
        {
            QList<int> empty_mics;
            bool onMic = false;
            for(auto it = mic_list_.cbegin(); it != mic_list_.cend(); it++)
            {
                qint64 userid = getParam(*it, cmd_param_uid).toLongLong();
                if(!userid)
                {
                    int micid = getParam(*it, cmd_param_mid).toInt();
                    if(micid > 0)
                        empty_mics.append(micid);
                    continue;
                }
                else if(userid == uid)
                {
                    onMic = true;
                    //在麦上
                    if(uid != myid)
                    {
                        action = menu->addAction(QObject::trECSUTF8("关闭视频"), this, SLOT(slot_free_mic()));
                        action->setData(uid);
                    }
                    else
                        action = menu->addAction(QObject::trECSUTF8("关闭视频"), ui->button_camera, SLOT(click()));
                }
            }
            //不在麦上
            if(!onMic)
            {
                if(apply_list_.contains(uid))
                {
                    //等待中
                    if(uid != myid)
                    {
                        action = menu->addAction(QObject::trECSUTF8("取消等待"), this, SLOT(slot_free_mic()));
                        action->setData(uid);
                    }
                    else
                        action = menu->addAction(QObject::trECSUTF8("取消等待"), ui->button_camera, SLOT(click()));
                }
                else if(uid != myid)
                {
                    action = menu->addAction(QObject::trECSUTF8("分享视频"));
                    connect(action, &QAction::triggered, this, [this, uid](){
                        ClientCallback::instance()->channel_apply_video(getId(), uid);
                    });
                }
                else
                    action = menu->addAction(QObject::trECSUTF8("分享视频"), ui->button_camera, SLOT(click()));

                auto submenu = menu->addMenu(QObject::trECSUTF8("分享到视频"));
                QVariantList varList;
                varList << QVariant(uid) << QVariant();
                QVariant &v2 = varList.last();
                foreach (const auto &mic, mic_list_) {
                    int key = getParam(mic, cmd_param_mic_id).toInt();
                    v2.setValue(key);
                    submenu->addAction(QObject::trECSUTF8("视频") + QString::number(key), this, SLOT(slot_grant_mic()))->setData(varList);
                }
            }
        }

        if(action)
            menu->popup(ui->list_online_user->mapToGlobal(pos));
        else
            delete menu;
    }
}
